package me.baicai.weixin.provider.service.impl;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import me.baicai.weixin.application.BasicService;
import me.baicai.weixin.application.Result;
import me.baicai.weixin.conf.IdentityKey;
import me.baicai.weixin.conf.OrderKey;
import me.baicai.weixin.conf.WeiXinKey;
import me.baicai.weixin.entity.gcb.PageEntity;
import me.baicai.weixin.entity.gcb.Query;
import me.baicai.weixin.entity.gcb.Withdrawal;
import me.baicai.weixin.entity.identity.Identity;
import me.baicai.weixin.entity.order.Account;
import me.baicai.weixin.entity.order.MoneyLog;
import me.baicai.weixin.entity.order.Order;
import me.baicai.weixin.identity.repository.*;
import me.baicai.weixin.provider.repository.WithdrawalRepository;
import me.baicai.weixin.provider.service.WeixinService;
import me.baicai.weixin.utils.WeiXinUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.*;


@Slf4j
@Service
public class WeixinServiceImpl extends BasicService implements WeixinService {
    @Autowired
    private AccountRepository accountRepository;

    @Autowired
    private MoneyLogRepository moneyLogRepository;

    @Autowired
    private WithdrawalRepository withdrawalRepository;

    @Autowired
    private LoginRepository loginRepository;

    @Autowired
    private AgentRepository agentRepository;

    @Autowired
    private EmployeeRepository employeeRepository;

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private DeviceRepository deviceRepository;

    @Override
    public Result applyWithdrawals(String openid, float amount) {
        Identity identity = loginRepository.findByOpenid(openid);
        Account account = identity.getAccount();
        if (null == account)
            return this.error("账户异常!");
        if (account.getBalance() < amount)
            return this.error("余额不足!");

        float charge = amount * withdrawalRepository.getRate();

        MoneyLog moneyLog = new MoneyLog();
        Withdrawal withdrawal = new Withdrawal();

        if (account.getBalance() >= (amount + charge)) {
            account.setBalance(account.getBalance() - (amount + charge));
            moneyLog.setAmount(amount + charge);
            moneyLog.setRemark(
                    "申请用户提现金额 : " + amount + " |手续费 : " + charge + " |实际到账金额 " + amount);
            withdrawal.setActualamount(amount);
            withdrawal.setType(OrderKey.PAY_余额);
        } else {
            account.setBalance(account.getBalance() - amount);
            moneyLog.setAmount(amount);
            moneyLog.setRemark(
                    "申请用户提现金额 : " + amount + " |手续费 : " + charge + " |实际到账金额 " + (amount - charge));
            withdrawal.setActualamount(amount - charge);
            withdrawal.setType(identity.getType());
            withdrawal.setType(OrderKey.订单金额);
        }

        accountRepository.saveAndFlush(account);
        moneyLog.setTargetid(openid);
        moneyLog.setTargettype(identity.getType());
        moneyLog.setCreated(new Date());
        moneyLog.setOrdersrc(OrderKey.SEC_提现);
        moneyLog.setMoneytype(OrderKey.SEC_支出);
        moneyLogRepository.saveAndFlush(moneyLog);

        withdrawal.setAmount(amount);
        withdrawal.setCharge(charge);
        withdrawal.setOpenid(openid);
        withdrawal.setCeated(new Date());
        withdrawal.setStatus(OrderKey.等待提现);
        withdrawal.setIdentitytype(identity.getType());
        withdrawal.setMoneyid(moneyLog.getId());
        withdrawal.setUid(identity.getId());
        withdrawal.setUpdated(withdrawal.getCeated());

        switch (identity.getType()) {
            case IdentityKey.agent:
                withdrawal.setName(identity.getNickName() + "【 " +
                        agentRepository.findByOpenid(identity.getOpenid()).getName() +
                        " 】");
                break;
            case IdentityKey.salesman:
                withdrawal.setName(identity.getNickName() + "【 " +
                        employeeRepository.findEmployeeByOpenid(
                                identity.getOpenid()).getName() + " 】");
                break;
            case IdentityKey.engineer:
                withdrawal.setName(identity.getNickName() + "【 " +
                        employeeRepository.findEmployeeByOpenid(
                                identity.getOpenid()).getName() + " 】");
                break;
            default:
                withdrawal.setName(identity.getNickName() + "【 " + identity.getName() + " 】");
        }

        withdrawalRepository.save(withdrawal);

        // 发送卡片通知
        return this.success("提交成功， 等待客服审核");
    }

    @Override
    public Result withdrawalRecord(String openid, String value, Integer page, String type,
                                   String status) {
        Pageable pageable = new PageEntity(page, 10, Sort.Direction.DESC, "updated");

            if (type.equalsIgnoreCase("admin")) // 代表审核人员想查看
            {
                if (StringUtils.isEmpty(value)) {
                    return this.success(withdrawalRepository.findAllByStatus(status, pageable));
                } else {
                    return this.success(withdrawalRepository.findAllByStatus(status, "%" + value + "%", pageable));
                }
            } else {
                return this.success(withdrawalRepository.findAllByOpenidAndStatus(openid, status, pageable));
            }
    }

    @Override
    public Result approvalWithdrawal(String openid, Integer id, String type) {
        Withdrawal withdrawal = withdrawalRepository.getWithdrawalById(id);

        if (null == withdrawal)
            return error("数据不存在!");

        if (!withdrawal.getStatus().equalsIgnoreCase(OrderKey.等待提现))
            return error("此条数据已经处理!");

        if (type.equalsIgnoreCase(OrderKey.同意提现)) {
            if (withdrawal.getOpenid().equalsIgnoreCase("oSMQR5QUdgu-_HW2T1wcWQes4T2U"))
                return error(500,"该账号存在风险,该笔交易已经拦截");

            withdrawal.setStatus(OrderKey.同意提现);
            SortedMap<String, String> signParams = new TreeMap<String, String>();
            signParams.put("mch_appid", WeiXinKey.appid);                       //  app_id
            signParams.put("mchid", WeiXinKey.mchid);                           //  微信商户账号
            signParams.put("device_info", withdrawal.getOpenid());              //  微信商户账号
            signParams.put("nonce_str",
                    UUID.randomUUID().toString().replaceAll("-", ""));//32位不重复订单
            signParams.put("partner_trade_no", "TX" + withdrawal.getId());     //  商户订单号
            signParams.put("openid", withdrawal.getOpenid());                   //  用户ID
            signParams.put("check_name",
                    "NO_CHECK");                        // NO_CHECK：不校验真实姓名 FORCE_CHECK：强校验真实姓名
            signParams.put("amount",
                    ((int) (withdrawal.getActualamount() * 100)) + "");//   支付金额 单位为分
            signParams.put("desc", "东莞市共城物联入帐金额");
            signParams.put("sign", WeiXinUtils.MD5(signParams));
            String request = WeiXinUtils.MapToXml(signParams);
            JSONObject jsonObject = null;
            try {
                jsonObject = WeiXinUtils.convertXmlIntoJSONObject(
                        WeiXinUtils.callWeiXin(request, WeiXinKey.withdrawal));
                log.info(new Date() + " 微信提现记录 : " + jsonObject);
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (null == jsonObject)
                return this.error();
            if (jsonObject.getString("return_code").equalsIgnoreCase("FAIL"))
                return this.error("参数错误 提现失败");
            if (jsonObject.getString("result_code").equalsIgnoreCase("FAIL"))
                return this.error(jsonObject.getString("err_code_des"));
            withdrawal.setResp(jsonObject.toJSONString());
            withdrawal.setUpdated(new Date());
        } else {
            withdrawal.setStatus(OrderKey.拒绝提现);
            Account account = accountRepository.findAccountByOpenid(withdrawal.getOpenid());
            account.setBalance(account.getBalance() + withdrawal.getActualamount() + withdrawal.getCharge());
            moneyLogRepository.deleteMoneyLogById(withdrawal.getMoneyid());
            withdrawal.setUpdated(new Date());
        }
        withdrawalRepository.save(withdrawal);
        return this.success("处理成功!");
    }

    @Override
    public Result refundOrder(String openid, String id) {
        Order order = orderRepository.getOrderById(id);
        if (null == order)
            return this.error("不存在的订单");

        if (order.getOrderstatus().equals(OrderKey.取消并且退款))
            return this.error("订单状态取消并且退款");

        List<MoneyLog> moneyLogs = moneyLogRepository.getMoneyLogsByOrderid(order.getId());

        if (order.getPaytype().equalsIgnoreCase(OrderKey.PAY_微信)) {

            SortedMap<String, String> signParams = new TreeMap<String, String>();
            signParams.put("appid", WeiXinKey.appid);//app_id
            signParams.put("mch_id", WeiXinKey.mchid);//微信商户账号
            signParams.put("nonce_str",
                    UUID.randomUUID().toString().replaceAll("-", ""));//32位不重复的编号
            signParams.put("out_refund_no", order.getId());//回调页面
            signParams.put("out_trade_no", order.getId());//订单编号
            signParams.put("refund_fee", ((int) (order.getAmount() * 100)) + "");//订单编号
            signParams.put("total_fee", ((int) (order.getAmount() * 100)) + "");//支付金额 单位为分
            signParams.put("sign", WeiXinUtils.MD5(signParams));
            String request = WeiXinUtils.MapToXml(signParams);
            JSONObject jsonObject = null;
            try {
                jsonObject = WeiXinUtils.convertXmlIntoJSONObject(
                        WeiXinUtils.callWeiXin(request, WeiXinKey.refund));
                log.info(new Date() + " 微信退款记录 : " + jsonObject);
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (null == jsonObject)
                return this.error();
            order.setCallback(jsonObject.toJSONString());

        } else {
            Account account = accountRepository.findAccountByOpenid(order.getCustomerid());
            account.setBalance(account.getBalance() + order.getAmount());
            accountRepository.saveAndFlush(account);
        }

        moneyLogs.forEach(arr -> {
            Account account = accountRepository.findAccountByOpenid(arr.getTargetid());
            account.setBalance(account.getBalance() - arr.getAmount());
            accountRepository.saveAndFlush(account);
        });

        moneyLogRepository.deleteAllByOrderid(order.getId());
        order.setOrderstatus(OrderKey.取消并且退款);
        orderRepository.save(order);
        return this.success();
    }

    @Override
    public Result withdrawalRecord(Query query) {
        Pageable pageable = new PageEntity(query.getPage(), query.getSize(), Sort.Direction.DESC,
                "id");

        if (query.getType().equalsIgnoreCase("all")) {
            if (StringUtils.isEmpty(query.getValue())) {
                return this.success(
                        withdrawalRepository.findAll(pageable));
            } else {
                return this.success(
                        withdrawalRepository.findAll("%" + query.getValue() + "%", pageable));
            }
        } else {
            if (StringUtils.isEmpty(query.getValue())) {
                return this.success(
                        withdrawalRepository.findAllByStatus(query.getType(), pageable));
            } else {
                return this.success(
                        withdrawalRepository.findAll(query.getType(), "%" + query.getValue() + "%",
                                pageable));
            }
        }
    }

    @Override
    public Result allDevice(Integer page, String sn) {
        Pageable pageable = new PageEntity(page, 10, Sort.Direction.DESC,
                "id");
        if (StringUtils.isEmpty(sn))
            return this.success(deviceRepository.findAllDevice(pageable));
        else
            return this.success(deviceRepository.findByPCSn(sn, pageable));
    }

    @Override
    public Result getRate() {
        return this.success(withdrawalRepository.getRate());
    }
}
